package snake;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;

public class GamePanel extends JPanel implements KeyListener,ActionListener{
    //蛇的长度
    private int length;
    private int[] snakeX;//蛇身的x坐标
    private int[] snakeY;//蛇身的Y坐标
    private String fx;//小蛇的方向
    //食物的位置
    private int[] foodX;
    private int[] foodY;
    //糖果的位置
    private int[] candyX;
    private int[] candyY;
    //炸弹
    private int[] bombX;
    private int[] bombY;

    private Random random = new Random();

    //游戏状态
    private boolean isFail;//游戏是否失败
    private boolean isStart;//游戏是否开始

    //游戏得分
    private int score;
    //分数变化特效(不用保存为游戏数据)
    private String str = "";
    private int strX = 0;
    private int strY = 0;

    //创建一个计时器，延迟一段delay毫秒就执行第一次任务
    private int delay;
    private Timer timer ;//设置为100毫秒刷新一次

    //游戏数据
    private GameData gameData;
    //构造器
    public GamePanel(){
        init();
        this.setFocusable(true);//获取焦点事件,注意该代码应该写到setVisible()方法后面，否则键盘监听器可能会失效
        this.addKeyListener(this);
        timer = new Timer(delay, this);
        timer.start();//开启计时器
    }
    public GamePanel(GameData gameData){

        initByGameData(gameData);
        this.setFocusable(true);//获取焦点事件,注意该代码应该写到setVisible()方法后面，否则键盘监听器可能会失效
        this.addKeyListener(this);
        timer = new Timer(delay, this);
        timer.start();//开启计时器
    }
    //初始化蛇的数据
    public void init(){
        //初始化蛇的数据
        length = 3;
        snakeX = new int[600];
        snakeY = new int[500];
        snakeX[0] = 100;snakeY[0] = 100;//头的坐标
        snakeX[1] = 75;snakeY[1] = 100;//第一节身体
        snakeX[2] = 50;snakeY[2] = 100;//第二节身体
        fx = "R";//初始化方向向右

        //初始化游戏状态
        isStart = false;//初始化游戏未开始
        isFail = false;//初始化游戏未失败
        score = 0;//游戏得分

        //初始化食物
        foodX = new int[10];//25+25*random.nextInt(34);
        foodY = new int[10];//75+25*random.nextInt(26);
        for (int i = 0; i < foodX.length; i++) {
            foodX[i] = 25+25*random.nextInt(34);
            foodY[i] = 75+25*random.nextInt(26);
        }
        bombY = new int[4];
        bombX = new int[4];
        for (int i = 0; i <bombX.length ; i++) {
            bombX[i] = 25+25*random.nextInt(34);
            bombY[i] = 75+25*random.nextInt(26);
        }
        candyX = new int[3];
        candyY = new int[3];
        for (int i = 0; i <candyX.length ; i++) {
            candyX[i] = 25+25*random.nextInt(34);
            candyY[i] = 75+25*random.nextInt(26);
        }

        delay = 100;

    }
    public void initByGameData(GameData gameData){
        //通过数据包初始化数据
        init();
        this.length = gameData.getLength();
        this.isFail = gameData.isFail();
        this.foodX = gameData.getFoodX();
        this.foodY = gameData.getFoodY();
        this.delay = gameData.getDelay();
        this.str = gameData.getStr();
        this.strY = gameData.getStrY();
        this.strX = gameData.getStrX();
        this.candyY = gameData.getCandyY();
        this.candyX = gameData.getCandyX();
        this.score = gameData.getScore();
        this.snakeX = gameData.getSnakeX();
        this.snakeY = gameData.getSnakeY();
        this.fx = gameData.getFx();
        this.isStart = gameData.isStart();
        this.bombY = gameData.getBombY();
        this.bombX = gameData.getBombX();
    }
    public GameData getGameData(){
        //打包游戏数据，用于储存
        gameData=new GameData();
        gameData.setScore(this.score);
        gameData.setFail(this.isFail);
        gameData.setStart(this.isStart);
        gameData.setDelay(this.delay);

        gameData.setFail(this.isFail);
        gameData.setFoodY(this.foodY);
        gameData.setFoodY(this.foodY);
        gameData.setCandyX(this.candyX);
        gameData.setCandyY(this.candyY);
        gameData.setBombX(this.bombX);
        gameData.setBombY(this.bombY);
        gameData.setSnakeX(this.snakeX);
        gameData.setSnakeY(this.candyY);
        gameData.setFx(this.fx);
        gameData.setStr(this.str);
        gameData.setSnakeY(this.snakeY);
        gameData.setStrX(this.strX);


        return gameData;
    }

    //用于绘制游戏中的的所有东西
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);//有清屏的作用

        //画初始的游戏面板
        this.setBackground(Color.white);
        ImageData.header.paintIcon(this,g,25,11);
        g.fillRect(25,75,850,650);//游戏界面
        g.setColor(Color.white);
        g.setFont(new Font("微软雅黑",Font.BOLD,18));
        g.drawString("方向键控制蛇，长按加速",60,35);
        //画得分
        g.setColor(Color.white);
        g.setFont(new Font("微软雅黑",Font.BOLD,18));
        g.drawString("长度："+length,750,35);
        g.drawString("得分："+score,750,55);

        //画特效
        if (strX !=0 && strY !=0){
            g.setColor(Color.RED);
            g.setFont(new Font("宋体",Font.BOLD,25));
            g.drawString(str,strX,strY);
            //画完就重置
            strX = 0;strY = 0;
        }
        //画食物
        for (int i = 0; i <foodX.length ; i++) {
            //画普通食物
            ImageData.food.paintIcon(this,g,foodX[i],foodY[i]);
        }
        for (int i = 0; i <bombX.length ; i++) {
            //画炸弹
            ImageData.bomb.paintIcon(this,g,bombX[i],bombY[i]);
        }

        for (int i = 0; i <candyX.length ; i++) {
            //画高级食物
            ImageData.candy.paintIcon(this,g,candyX[i],candyY[i]);
        }
        //画蛇
        //画蛇头
        if ("R".equals(fx)){
            ImageData.right.paintIcon(this,g,snakeX[0],snakeY[0]);//蛇头
        }else if ("L".equals(fx)){
            ImageData.left.paintIcon(this,g,snakeX[0],snakeY[0]);//蛇头
        }else if ("U".equals(fx)){
            ImageData.up.paintIcon(this,g,snakeX[0],snakeY[0]);//蛇头
        }else if ("D".equals(fx)){
            ImageData.down.paintIcon(this,g,snakeX[0],snakeY[0]);//蛇头
        }
        //画蛇身
        for (int i = 1; i < length; i++) {
            //从小蛇的第一节身体开始画
            ImageData.body.paintIcon(this,g,snakeX[i],snakeY[i]);//蛇身体
        }

        //游戏状态
        if (isStart==false){
            g.setColor(Color.white);
            //参数：本机字体名称，字体样式，字体大小
            g.setFont(new Font("宋体",Font.BOLD,40));//宋体，加粗，大小40
            g.drawString("按下空格开始游戏",300,300);
        }
        if (isFail){
            g.setColor(Color.RED);
            //参数：本机字体名称，字体样式，字体大小
            g.setFont(new Font("宋体",Font.BOLD,40));//宋体，加粗，大小40
            g.drawString("游戏失败，按下空格重新开始",150,300);
        }
    }
    @Override
    public void keyTyped(KeyEvent e) {

    }
    @Override
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();
        //控制游戏状态
        if (keyCode == KeyEvent.VK_SPACE){//如果按下的是空格
            if(isFail){
                init();
            }else {
                isStart = !isStart;//取反
                repaint();//重画(只要是更新游戏状态那几个字)
            }
        //控制方向
        }else if (keyCode==KeyEvent.VK_UP){
            if ("U".equals(fx)){
                timer.setDelay(delay/2);
            }
            if (!isContrary("U")){
                fx = "U";
            }
        }else if (keyCode==KeyEvent.VK_DOWN){
            if ("D".equals(fx)){
                timer.setDelay(delay/2);
            }
            if (!isContrary("D")){
                fx = "D";
            }

        }else if (keyCode==KeyEvent.VK_LEFT){
            if ("L".equals(fx)){
                timer.setDelay(delay/2);
            }
            if (!isContrary("L")){
                fx = "L";
            }
        }else if (keyCode==KeyEvent.VK_RIGHT){
            if ("R".equals(fx)){
                timer.setDelay(delay/2);
            }
            if (!isContrary("R")){
                fx = "R";
            }
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
        int keyCode = e.getKeyCode();
        if (keyCode==KeyEvent.VK_UP){
            if ("U".equals(fx)){
                timer.setDelay(delay);
            }
        }else if (keyCode==KeyEvent.VK_DOWN){
            if ("D".equals(fx)){
                timer.setDelay(delay);
            }
        }else if (keyCode==KeyEvent.VK_LEFT){
            if ("L".equals(fx)){
                timer.setDelay(delay);
            }
        }else if (keyCode==KeyEvent.VK_RIGHT){
            if ("R".equals(fx)){
                timer.setDelay(delay);
            }
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (isStart&&isFail == false){
            //吃食物
            for (int i = 0;i<foodX.length;i++){
                if (snakeX[0] == foodX[i] && snakeY[0] == foodY[i]){
                    length++;//吃到食物，蛇的长度+1
                    score+=10;
                    str = "+1";strX = foodX[i];strY = foodY[i]-15;
                    do {
                        foodX[i] = 25+25*random.nextInt(34);
                        foodY[i] = 75+25*random.nextInt(26);
                    }while (isInSnakes(foodX[i],foodY[i]));

                }
            }
            //吃炸弹
            for (int i = 0;i<bombX.length;i++){
                if (snakeX[0] == bombX[i] && snakeY[0] == bombY[i]){
                    length -= 3;//吃到炸弹，蛇的长度-3
                    score -= 30;//减三十分
                    str = "-3";strX = bombX[i];strY = bombY[i]-15;
                    do {
                        bombX[i] = 25+25*random.nextInt(34);
                        bombY[i] = 75+25*random.nextInt(26);
                    }while (isInSnakes(bombX[i],bombY[i]));
                }
            }
            //吃糖果
            for (int i = 0;i<candyX.length;i++){
                if (snakeX[0] == candyX[i] && snakeY[0] == candyY[i]){
                    length += 2;//吃到糖果，蛇的长度+2
                    score += 20;
                    str = "+2";strX = candyX[i];strY = candyY[i]-15;
                    do {
                        candyX[i] = 25+25*random.nextInt(34);
                        candyY[i] = 75+25*random.nextInt(26);
                    }while (isInSnakes(candyX[i],candyY[i]));
                }
            }
            //右移动
            for (int i = length-1; i >0; i--) {
                //从尾巴开始往前移动，后一节移动到前一节的位置
                snakeX[i] = snakeX[i-1];
                snakeY[i] = snakeY[i-1];
            }

            //控制移动,走向
            if ("R".equals(fx)){
                snakeX[0] = snakeX[0]+25;
                //边界判断
                if (snakeX[0]>850){//走出边界，又从另一边走出来
                    snakeX[0]=25;
                }
            }else if ("L".equals(fx)){
                 snakeX[0] = snakeX[0]-25;
                //边界判断
                 if (snakeX[0]<25){
                     snakeX[0]=850;
                 }
            }else if ("U".equals(fx)){
                 snakeY[0] = snakeY[0]-25;
                //边界判断
                if (snakeY[0]<75){
                    snakeY[0]=700;
                }
            }else if ("D".equals(fx)){
                snakeY[0] = snakeY[0]+25;
                //边界判断
                if (snakeY[0]>700){
                    snakeY[0] = 75;
                }
            }

            //失败判定
            for (int i = 1; i < length; i++) {
                if (snakeX[0]==snakeX[i]&&snakeY[0]==snakeY[i]){
                    //碰到自己
                    isFail = true;
                }
            }

            if (length<=0){
                //长度小于0；
                isFail = true;
            }
            repaint();//重画一次
        }
    }

    public boolean isContrary(String key){

        if ("U".equals(fx) && "D".equals(key)){
            return true;
        }else if ("L".equals(fx) && "R".equals(key)){
            return true;
        }else if ("R".equals(fx) && "L".equals(key)){
            return true;
        }else if ("D".equals(fx) && "U".equals(key)){
            return true;
        }else {
            return false;
        }
    }

    public boolean isInSnakes(int x , int y){
        boolean flag = false;
        for (int i = 0 ;i<snakeX.length;i++){
            if (x == snakeX[i] && y ==snakeY[i]){
                flag = true;
            }
        }
        return  flag;
    }
}
